package arithmetic.guaveTest;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.junit.jupiter.api.Test;

import com.google.common.primitives.Chars;

import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;

/**
 * https://github.com/jhalterman/expiringmap/
 * @author jiangfeng
 * Created on 2020-04-09
 */
public class TimerCall2 {
    static DateTimeFormatter d = DateTimeFormatter.ofPattern("mm-ss-SSS");
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor
                executor = new ThreadPoolExecutor(12*2, 12 * 2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20));


        ExpiringMap<String, LocalDateTime> map = ExpiringMap.builder().expirationPolicy(ExpirationPolicy.CREATED)
                .asyncExpirationListener((key, value) ->
                {
                    LocalDateTime now = LocalDateTime.now();
                    System.out.println(now.format(d)+" :" + key + "过期了"+
                             " 时长:" +
                                    (now.toInstant(ZoneOffset.of("+8")).toEpochMilli() - ((LocalDateTime) value)
                                    .toInstant(ZoneOffset.of("+8")).toEpochMilli()));
                })
                .expiration(10, TimeUnit.SECONDS) // 默认60s
                .variableExpiration()
                .build();

        // 打印
        executor.execute(()->{
            int emptyClose =3;
            int mapSize=0;
            while (true) {
                if (mapSize != (mapSize = map.size())) {
                    LocalDateTime now = LocalDateTime.now();
                    System.out.println(now.format(d)+" :"+
                            "现有缓存:" + map.entrySet().stream().map(a -> a.getKey() + ":" + a.getValue().format(d)).collect(
                                    Collectors.joining(" , ")));
                }
                /*try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/

                // 3次为空就关闭打印
                if (map.size() == 0) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if ((--emptyClose) == 0) {
                        break;
                    }
                } else {
                    emptyClose = 3;
                }

            }
        });


        // 第二次放入不会覆盖时间
        map.put("a", LocalDateTime.now(), 30, TimeUnit.SECONDS);
        TimeUnit.SECONDS.sleep(1);
        map.put("b", LocalDateTime.now(), 5, TimeUnit.SECONDS);
        TimeUnit.SECONDS.sleep(1);
        map.put("c", LocalDateTime.now(),  5, TimeUnit.SECONDS);
        map.put("d", LocalDateTime.now(),  1, TimeUnit.SECONDS);
        TimeUnit.SECONDS.sleep(1); // 测试下是否会覆盖
        map.put("a", LocalDateTime.now(),  10, TimeUnit.SECONDS);
        long a = map.getExpectedExpiration("a");
        System.out.println(a);
        map.put("c", LocalDateTime.now(),  5, TimeUnit.SECONDS);
        map.put("e", LocalDateTime.now(),  8, TimeUnit.SECONDS);
        map.put("f", LocalDateTime.now(),  9, TimeUnit.SECONDS);

        TimeUnit.SECONDS.sleep(20);

        // 慢慢放缓存
        executor.execute(()->{
            for (int i = 1; i <20;i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                map.put(""+Chars.checkedCast('a'+i), LocalDateTime.now());
            }
        });



        TimeUnit.SECONDS.sleep(1);

        // 慢慢放缓存
        executor.execute(()->{
            for (int i = 1; i <10;i++) {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                map.put(""+Chars.checkedCast('a'+i), LocalDateTime.now());
            }
        });






        //TimeUnit.SECONDS.sleep(300);

    }



    @Test
    public void shouldSupportVariableExpiration() throws InterruptedException {
        ExpiringMap<String, Object> cache = ExpiringMap.builder()
                .variableExpiration()
                .build();

        cache.put("hello", "world", ExpirationPolicy.CREATED, 1000L, TimeUnit.MILLISECONDS);
        cache.put("foo", "bar", ExpirationPolicy.CREATED, 3000L, TimeUnit.MILLISECONDS);

        // both keys are available in the first second
        assertEquals("world", cache.get("hello"));
        assertEquals("bar", cache.get("foo"));

        // after waiting 1 second, only "hello" should have expired
        Thread.sleep(1001L);
        assertNull(cache.get("hello"));
        assertEquals("bar", cache.get("foo"));  // <============   this fails

        // after waiting a total of 2 seconds, both keys should have expired
        Thread.sleep(1000L);
        assertNull(cache.get("hello"));
        assertNull(cache.get("bar"));
    }
}
